###############################################################################
# SuperLinks                                                                  #
# Copyright (c) 2000-2007 Greg Nolle (http://greg.nolle.co.uk)                #
###############################################################################
# This program is free software; you can redistribute it and/or modify it     #
# under the terms of the GNU General Public License as published by the Free  #
# Software Foundation; either version 2 of the License, or (at your option)   #
# any later version.                                                          #
#                                                                             #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   #
# more details.                                                               ##                                                                             #
# You should have received a copy of the GNU General Public License along     #
# with this program; if not, write to the Free Software Foundation, Inc.,     #
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.                 #
###############################################################################
# ControlPanel/CreateBackup.pm.pl -> CreateBackup module                      #
###############################################################################
# DON'T EDIT BELOW UNLESS YOU KNOW WHAT YOU'RE DOING!                         #
###############################################################################
package CP::CreateBackup;

BEGIN { require "System.pm.pl"; import System qw($SYSTEM); }
BEGIN { require "General.pm.pl"; import General qw($GENERAL); }
require "Error.pm.pl";
require "Standard.pm.pl";
require "Authenticate.pm.pl";
require "Logs.pm.pl";

use File::Path;
use File::Copy;
use File::Find;
use Cwd;
use Archive::Tar;
use strict;

require "ControlPanel/Output/CreateBackup.pm.pl";

sub new {
  my ($class) = @_;
  my $self    = {};
  return bless($self, $class);
}

sub DESTROY { }

###############################################################################
# show subroutine
sub show {
  my $self = shift;
  my %in = (DB => undef, @_);

  #----------------------------------------------------------------------#
  # Authenticating...                                                    #
  
  &Authenticate::CP(DB => $in{'DB'}, ACTION => "BACKUPS_CREATE");

  #----------------------------------------------------------------------#
  # Printing page...                                                     #

  my $Skin = Skin::CP::CreateBackup->new();

  &Standard::PrintHTMLHeader();
  print $Skin->show();
  
  return 1;
}

###############################################################################
# do subroutine
sub do {
  my $self = shift;
  my %in = (DB => undef, @_);

  #----------------------------------------------------------------------#
  # Authenticating...                                                    #
  
  &Authenticate::CP(DB => $in{'DB'}, ACTION => "BACKUPS_CREATE");

  #----------------------------------------------------------------------#
  # Preparing data...                                                    #

  my $Skin = Skin::CP::CreateBackup->new();

  &Standard::PrintHTMLHeader();  

  unless ($SL::QUERY{'do'}) {
    print $Skin->do();
    return 1;
  }

  my $Epoch = time;
  my $BackupDir = $SYSTEM->{'BACKUP_PATH'}."/SL-".$Epoch;

  &Standard::FileOpen(*LOG, "w", $BackupDir.".log");
  my $Log = Logs->new(HANDLE => *LOG, PRINT => 1);
  
  my $Exit = eval {
    sub {
      close(LOG);
      
      $Log->Footer();
      exit;
    }
  };
  
  $Log->Header();

  $Log->Line("", "uplevel");
  $Log->Line("Beginning backup of SuperLinks.\n\n", "element");
  
  $Log->Line("Creating directory for Backup ($BackupDir)... ", "element");
  mkdir($BackupDir, 0777) || ($Log->Line("Error: $!", "error") and &$Exit);
  chmod(0777, $BackupDir);
  $Log->Line("Done.", "success");

  opendir(DIR, "$SYSTEM->{'DB_PATH'}");
  my @Tables;
  foreach my $file (grep(/\.cfg$/, readdir(DIR))) {
    $file =~ m/^(.*)\.cfg$/;
    push(@Tables, $1);
  }
  closedir(DIR);

  foreach my $table (@Tables) {
    next if ($table eq "LanguageSets" && !$SL::QUERY{'FORM_BACKUP_LANGUAGESETS'});
    next if ($table eq "Skins" && !$SL::QUERY{'FORM_BACKUP_SKINS'});
    next if ($table eq "StyleSheets" && !$SL::QUERY{'FORM_BACKUP_STYLESHEETS'});
    next if ($table eq "TemplateSets" && !$SL::QUERY{'FORM_BACKUP_TEMPLATESETS'});
    $Log->Line("Backing-up \"".$table."\" table...", "element");
    $Log->Line("", "uplevel");
    if (
      $self->myBackupTable(
        $Log,
        DB      => $in{'DB'},
        TO      => $BackupDir,
        TABLE   => $table
      )
    ) {
      $Log->Line("", "downlevel");
    } else {
      &$Exit;
    }
  }

  if ($SL::QUERY{'FORM_BACKUP_LANGUAGESETS'}) {
    $Log->Line("Backing-up language sets... ", "element");
    
    mkdir("$BackupDir/LanguageSets/Files", 0777) || ($Log->Line("Error: $!", "error") and &$Exit);
    chmod(0777, "$BackupDir/LanguageSets/Files");
    my $cwd = cwd();
    
    my (@files, @directories);
    my $findsub = eval {
      sub {
        if (-f) {
          push(@files, $File::Find::name);
        } elsif (-d && $_ !~ /^\.\.?$/) {
          push(@directories, $File::Find::name);
        }
      }
    };

    chdir("$SL::PATH/Private/Skins/Language");
    find(\&$findsub, ".");
    chdir($cwd);

    foreach my $directory (sort @directories) {
      $directory =~ s/^\.\///;
      mkdir("$BackupDir/LanguageSets/Files/$directory", 0777) || ($Log->Line("Error: $!", "error") and &$Exit);
      chmod(0777, "$BackupDir/LanguageSets/Files/$directory");
    }
    foreach my $file (@files) {
      $file =~ s/^\.\///;
      copy("$SL::PATH/Private/Skins/Language/$file", "$BackupDir/LanguageSets/Files/$file") || ($Log->Line("Error: $!", "error") and &$Exit);
      chmod(0666, "$BackupDir/LanguageSets/Files/$file");
    }
    
    $Log->Line("Done.", "success");
  }
  
  if ($SL::QUERY{'FORM_BACKUP_TEMPLATESETS'}) {
    $Log->Line("Backing-up template sets... ", "element");
    
    mkdir("$BackupDir/TemplateSets/Files", 0777) || ($Log->Line("Error: $!", "error") and &$Exit);
    chmod(0777, "$BackupDir/TemplateSets/Files");
    my $cwd = cwd();
    
    my (@files, @directories);
    my $findsub = eval {
      sub {
        if (-f) {
          push(@files, $File::Find::name);
        } elsif (-d && $_ !~ /^\.\.?$/) {
          push(@directories, $File::Find::name);
        }
      }
    };

    chdir("$SL::PATH/Private/Skins/Templates");
    find(\&$findsub, ".");
    chdir($cwd);

    foreach my $directory (sort @directories) {
      $directory =~ s/^\.\///;
      mkdir("$BackupDir/TemplateSets/Files/$directory", 0777) || ($Log->Line("Error: $!", "error") and &$Exit);
      chmod(0777, "$BackupDir/TemplateSets/Files/$directory");
    }
    foreach my $file (@files) {
      $file =~ s/^\.\///;
      copy("$SL::PATH/Private/Skins/Templates/$file", "$BackupDir/TemplateSets/Files/$file") || ($Log->Line("Error: $!", "error") and &$Exit);
      chmod(0666, "$BackupDir/TemplateSets/Files/$file");
    }
    
    $Log->Line("Done.", "success");
  }

  if ($SL::QUERY{'FORM_COMPRESS'}) {
    $Log->Line("Packing the backup... ", "element");
    my $result = $self->myPack("SL-".$Epoch);
    if ($result == 1) {
      $Log->Line("Done.", "success");
      $Log->Line("Removing backup directory... ", "element");
      rmtree($BackupDir);
      $Log->Line("Done.", "success");
    } else {
      $Log->Line("Error: $result", "error");
    }
  }
  
  if ($SL::QUERY{'FORM_DESCRIPTION'}) {
    my $description = &Standard::HTMLize($SL::QUERY{'FORM_DESCRIPTION'});
    $Log->Line("Writing backup description file... ", "element");
    if (open(DESC, ">$BackupDir.txt")) {
      print DESC $description;
      close(DESC);
      $Log->Line("Done.", "success");
    } else {
      $Log->Line("Error: $!", "error");
    }
  }

  $Log->Line("\n\n", "");
  $Log->Line("All done!", "element");
  $Log->Line("", "downlevel");

  &$Exit;
}

###############################################################################
# myBackupTable subroutine
sub myBackupTable {
  my $self = shift;
  my $Log = shift;
  my %in = (DB => undef, TO => "", TABLE => "", @_);

  $Log->Line("Creating a backup directory for the table data... ", "element");
  mkdir ("$in{'TO'}/$in{'TABLE'}", 0777) || ($Log->Line("Error: $!", "error") and return);
  chmod (0777, "$in{'TO'}/$in{'TABLE'}");
  $Log->Line("Done.", "success");

  $Log->Line("Exporting the table... ", "element");

  if (my $Export = $in{'DB'}->Export(CFG => "$SYSTEM->{'DB_PATH'}/$in{'TABLE'}.cfg", TABLE => $in{'TABLE'})) {
    open (EXPORT, ">$in{'TO'}/$in{'TABLE'}/$in{'TABLE'}.export") || ($Log->Line("Error: $!", "error") and return);
    print EXPORT $Export;
    close(EXPORT);
    $Log->Line("Done.", "success");
  }	else {
    $Log->Line("Error: $in{'DB'}->{'ERROR'}", "error") and return;
  }

  $Log->Line("Copying the table's config file... ", "element");
  copy ("$SYSTEM->{'DB_PATH'}/$in{'TABLE'}.cfg", "$in{'TO'}/$in{'TABLE'}.cfg") || ($Log->Line("Error: $!", "error") and return);
  $Log->Line("Done.", "success");

  return 1;
}

###############################################################################
# myPack subroutine
sub myPack {
  my $self = shift;
  my ($Backup) = @_;

  my $Cwd = cwd();
  chdir($SYSTEM->{'BACKUP_PATH'});

  my @Files = $self->myExplore($SYSTEM->{'BACKUP_PATH'}, $Backup);

  my $Tar = Archive::Tar->new();
     $Tar->add_files(@Files) || (chdir($Cwd) and return $Archive::Tar::error);

  if ($Archive::Tar::compression) {
    $Tar->write("$Backup.tar.gz", 1);
  } else {
    $Tar->write("$Backup.tar");
  }

  chdir($Cwd);

  return 1;
}

###############################################################################
# myExplore subroutine
sub myExplore {
  my $self = shift;
  my ($Base, $Directory) = @_;

  my @Return;

  opendir(DIR, $Base."/".$Directory);
  my @List = readdir(DIR);
  closedir(DIR);

  foreach my $file (@List) {
    next if ($file =~ /^\.\.?$/);
    
    if (-d $Base."/".$Directory."/".$file) {
      push(@Return, $self->myExplore($Base, $Directory."/".$file));
    } else {
      push(@Return, $Directory."/".$file);
    }
  }
  
  return @Return;
}

1;